/**
* \file pico.y
* \brief gramática Yacc usada pelo parser para gerar a AST graças a ações semânticas. 
* \author Rafael Machado
* \author Ananias Tessaro
* \author Vinicius Schmitt
* \version 2
* \date 16/06/2011
*/

%{
  /* Aqui, pode-se inserir qualquer codigo C necessario ah compilacao
   * final do parser. Sera copiado tal como esta no inicio do y.tab.c
   * gerado por Yacc.
   */
  #include <stdio.h>
  #include <stdlib.h>
  #include "symbol_table.h"
  #include "lista.h"
  #include "node.h"



char* lexema;
symbol_t symbol_table;
int deslocamento=0;

%}

%union {
  char* cadeia;
  struct _node * no;
}

/*Terminal*/
%token IPRINT
%token REAL
%token FOR
%token NEXT
%token REPEAT
%token UNTIL
%token CONST
%token CASE
%token INT
%token DOUBLE
%token CHAR
%token QUOTE
%token DQUOTE
%token LE
%token GE
%token EQ
%token NE
%token AND
%token OR
%token NOT
%token IF
%token THEN
%token ELSE
%token WHILE
%token END
%token TRUE
%token FALSE
%token<cadeia> INT_LIT
%token<cadeia> F_LIT
%token<cadeia> IDF

/*Não Terminal*/
%type<no> code 
%type<no> acoes
%type<no> comando
%type<no> enunciado
%type<no> expr
%type<no> lvalue
%type<no> declaracoes
%type<no> declaracao
%type<no> listadeclaracao
%type<no> tipo
%type<no> tipounico
%type<no> tipolista
%type<no> listadupla
%type<no> listaexpr
%type<no> chamaproc
%type<no> fiminstcontrole
%type<no> expbool

%left '+' '-'
%left '*' '/'
%left OR
%left AND
%left NOT


%start code

 /* A completar com seus tokens - compilar com 'yacc -d' */

%%
code: declaracoes acoes 
            {
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=$1;
                children[1]=$2;
                $$=create_node(0, program_node, "__code", $2->attribute, 2, children);
                syntax_tree = $$;
            }
    | acoes { $$ = $1; syntax_tree = $$;}
    ;

declaracoes: declaracao ';' 
            { 
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=$1;
                children[1]=create_leaf(0, ';', ";", NULL);
                $$=create_node(0, decl_node, "__declaracoes", NULL, 2, children);
            }
           | declaracoes declaracao ';'
            {
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=$1;
                children[1]=$2;
                children[2]=create_leaf(0, ';', ";", NULL);
                $$=create_node(0, decl_node, "__declaracoes", NULL, 3, children);
            }
           ;

declaracao: listadeclaracao ':' tipo {
                insert_table($1,$3);
                
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=$1;
                children[1]=create_leaf(0, ':', ":", NULL);
                children[2]=$3;
                $$=create_node(0, decl_node, "__declaracao", NULL, 3, children);
            }
;

listadeclaracao: IDF  { $$ = create_leaf(0, idf_node, $1, NULL); } 
               | IDF ',' listadeclaracao  
            {
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=create_leaf(0, idf_node, $1, NULL);
                children[1]=create_leaf(0, ',', ",", NULL);
                children[2]=$3;
                $$=create_node(0, decl_list_node, "__listadeclaracao", NULL, 3, children);
            }
               ;

tipo: tipounico { $$ = $1;}
    | tipolista { $$ = $1;}
    ;

tipounico: INT        {$$=create_leaf(0, int_kw_node, "int", NULL);}
         | DOUBLE     {$$=create_leaf(0, double_kw_node, "double", NULL);}
         | REAL      {$$=create_leaf(0, real_kw_node, "float", NULL);}
         | CHAR       {$$=create_leaf(0, char_kw_node, "char", NULL);}
         ;

tipolista: INT '[' listadupla ']' 
            {
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=create_leaf(0, int_kw_node, "int", NULL);
                children[1]=create_leaf(0, '[', "[", NULL);
                children[2]=$3;
                children[3]=create_leaf(0, ']', "]", NULL);
                $$=create_node(0,tipo_list_node, "__tipolista", $3->attribute, 4, children);
            }
         | DOUBLE '[' listadupla ']'
            {
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=create_leaf(0, double_kw_node, "double", NULL);
                children[1]=create_leaf(0, '[', "[", NULL);
                children[2]=$3;
                children[3]=create_leaf(0, ']', "]", NULL);
                $$=create_node(0,tipo_list_node, "__tipolista", $3->attribute, 4, children);
            }
         | REAL '[' listadupla ']'
            {
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=create_leaf(0, real_kw_node, "real", NULL);
                children[1]=create_leaf(0, '[', "[", NULL);
                children[2]=$3;
                children[3]=create_leaf(0, ']', "]", NULL);
                $$=create_node(0,tipo_list_node, "__tipolista", $3->attribute, 4, children);
            }
         | CHAR '[' listadupla ']'
            {
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=create_leaf(0, char_kw_node, "char", NULL);
                children[1]=create_leaf(0, '[', "[", NULL);
                children[2]=$3;
                children[3]=create_leaf(0, ']', "]", NULL);
                $$=create_node(0,tipo_list_node, "__tipolista", $3->attribute, 4, children);
            }
         ;

listadupla: INT_LIT ':' INT_LIT 
            {
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));
                attribute->array=(struct array_info*)malloc(sizeof(struct array_info));
                
                attribute->array->start=atoi($1);
                attribute->array->end=atoi($3);
                attribute->array->tam=attribute->array->end - attribute->array->start+1;
                attribute->array->next=NULL;
                
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=create_leaf(0, int_node, $1, NULL);
                children[1]=create_leaf(0, ':', ":", NULL);
                children[2]=create_leaf(0, int_node, $3, NULL);
                $$=create_node(0,listdupla_node, "__listadupla", attribute, 3, children);
                
               
            }
          | INT_LIT ':' INT_LIT ',' listadupla
            {
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));
                attribute->array=(struct array_info*)malloc(sizeof(struct array_info));
                
                attribute->array->start=atoi($1);
                attribute->array->end=atoi($3);
                attribute->array->tam=attribute->array->end - attribute->array->start+1;
                attribute->array->next=$5->attribute->array;

                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=create_leaf(0, int_node, $1, NULL);
                children[1]=create_leaf(0, ':', ":", NULL);
                                children[2]=create_leaf(0, int_node, $3, NULL);
                children[3]=create_leaf(0, ',', ",", NULL);
                children[4]=$5;
                $$=create_node(0,listdupla_node, "__listadupla", attribute, 5, children);
            }
          ;

acoes: comando ';'  
            {
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=$1;
                children[1]=create_leaf(0, ';', ";", NULL);
                $$=create_node(0, acoes_node, "__acoes", $1->attribute, 2, children);
                
                
            }
    | comando ';' acoes
            {
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));
                attribute->code=$1->attribute->code;

                cat_tac(&attribute->code, &$3->attribute->code);
 
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=$1;
                children[1]=create_leaf(0, ';', ";", NULL);
                children[2]=$3;
                $$=create_node(0, acoes_node, "__acoes", attribute, 3, children);
            }
    ;

comando: lvalue '=' expr
            {

                if($1->attribute->type==TYPE_INT && ($3->attribute->type==TYPE_REAL || $3->attribute->type==TYPE_DOUBLE))
                {
                    yyerror("Incompatibilidade de tipos.");
                    exit(-1);                
                }
                if($1->attribute->type!=$3->attribute->type && ($1->attribute->type==TYPE_CHAR || $3->attribute->type==TYPE_CHAR))
                {
                    yyerror("Incompatibilidade de tipos.");
                    exit(-1);                
                }


            
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));
                
                attribute->code=$1->attribute->code;
                cat_tac(&attribute->code, &$3->attribute->code);
                
                struct tac*  new_tac = create_inst_tac(TAC_EXPR, $1->attribute->local, $3->attribute->local,"","");

                append_inst_tac(&attribute->code, new_tac); 
                                            
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=$1;
                children[1]=create_leaf(0, '=', ":=", NULL);
                children[2]=$3;
                $$=create_node(0, lvalue_node, "__comando", attribute, 3, children);
            }
       | enunciado { $$ = $1;}
       ;

lvalue: IDF    
            { 
                entry_t* p = lookup(symbol_table, $1) ;
                if(p==NULL)
                {
                    yyerror("Identificador invalido var.");
                    exit(-1);
                }
                
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));
                char* desloc = malloc(sizeof(char)*(10));

	            if(p->desloc<10)
	                sprintf(desloc,"00%d(SP)",p->desloc);
	            else if(p->desloc<100)
	                sprintf(desloc,"0%d(SP)",p->desloc);
                else
                    sprintf(desloc,"%d(SP)",p->desloc);
                
                attribute->local=desloc;
                attribute->type=p->type;
                $$ = create_leaf(0, idf_node, $1, attribute); 
            } 

      | IDF '[' listaexpr ']' 
            {
                entry_t* p = lookup(symbol_table, $1) ;
                if(p==NULL)
                {
                    yyerror("Identificador invalido [array].");
                    exit(-1);
                }

                Attr*  attribute = (Attr*) malloc(sizeof(Attr));
                char* desloc = malloc(sizeof(char)*(10));


                attribute->code=$3->attribute->code;
                attribute->type=p->type;
                attribute->local=novo_tmp(TYPE_INT);

                
                append_inst_tac(&attribute->code, create_inst_tac(TAC_EXPR, attribute->local, "0","", ""));                 
                
                char* temp=(char*)malloc(sizeof(char)*16);
                char* aux=(char*)malloc(sizeof(char)*16);

                temp=novo_tmp(TYPE_INT);
                
                Node*  node_aux = $3;
                
                struct array_info* arr = p->extra;
                while(arr!=NULL)
                {
                    sprintf(aux,"%d",arr->off);
                    append_inst_tac(&attribute->code, create_inst_tac(TAC_EXPR, temp, aux,"MUL", node_aux->attribute->local));                 
                    append_inst_tac(&attribute->code, create_inst_tac(TAC_EXPR, attribute->local, attribute->local,"ADD", temp));                 
                    arr=arr->next;
                    if(node_aux->children!=NULL)
                        node_aux=node_aux->children[2];
                }                
                
                sprintf(aux,"%d",p->extra->offset);
                append_inst_tac(&attribute->code, create_inst_tac(TAC_EXPR, attribute->local, attribute->local,"SUB", aux));                 
       
                if(p->type==TYPE_INT)
                    sprintf(aux,"%d",4);
                else if(p->type==TYPE_INT)
                    sprintf(aux,"%d",1);
                else
                    sprintf(aux,"%d",8);
               
                append_inst_tac(&attribute->code, create_inst_tac(TAC_EXPR, attribute->local, attribute->local,"MUL", aux));                 
                               
                if(p->desloc<10)
                    sprintf(temp,"%s(00%d(SP))",attribute->local,p->desloc);
                else if(p->desloc<100)
                    sprintf(temp,"%s(0%d(SP))",attribute->local,p->desloc);
                else
                    sprintf(temp,"%s(%d(SP))",attribute->local,p->desloc);
                
                
                attribute->local=temp;   
                                        
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=create_leaf(0, idf_node, $1, NULL);
                children[1]=create_leaf(0, '[', "[", NULL);
                children[2]=$3;
                children[3]=create_leaf(0, ']', "]", NULL);
                $$=create_node(0, lvalue_node, "__lvalue", attribute, 4, children);
            }
      ;

listaexpr: expr        { $$=$1; }
       | expr ',' listaexpr
            {
                        Attr*  attribute = (Attr*) malloc(sizeof(Attr));
                        attribute->local=$1->attribute->local;
                        attribute->code=$1->attribute->code;
                        cat_tac(&attribute->code, &$3->attribute->code);
                        
                        Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                        children[0]=$1;
                        children[1]=create_leaf(0, ',', ",", NULL);
                        children[2]=$3;
                        $$=create_node(0, listaexpr_node, "__listaexpr", attribute, 3, children);
            }
       ;

expr: expr '+' expr  
            {          
                                     
                        Attr*  attribute = (Attr*) malloc(sizeof(Attr));


                        struct node_tac*  nodetac=NULL;
                        struct tac*  new_tac = NULL;

                        if($1->attribute->type==0 || $3->attribute->type==0 || $1->attribute->type==TYPE_CHAR || $3->attribute->type==TYPE_CHAR)
                        {
                            yyerror("Tipo invalido.");
                            exit(-1);                            
                        }
                        if($1->attribute->type==TYPE_INT && $3->attribute->type==TYPE_INT)
                        {
                            attribute->type=TYPE_INT;
                            attribute->local=novo_tmp(TYPE_INT);
                            new_tac=create_inst_tac(TAC_EXPR,attribute->local, $1->attribute->local,"ADD", $3->attribute->local);
                        }
                        else
                        {
                            if($1->attribute->type==TYPE_DOUBLE || $3->attribute->type==TYPE_DOUBLE)
                            {
                                attribute->type=TYPE_DOUBLE;
                                attribute->local=novo_tmp(TYPE_DOUBLE);
                            }
                            else
                            {
                                attribute->type=TYPE_REAL;
                                attribute->local=novo_tmp(TYPE_REAL);
                            }
                            new_tac=create_inst_tac(TAC_EXPR,attribute->local, $1->attribute->local,"FADD", $3->attribute->local);
                        }
                        
                        cat_tac(&nodetac, &$1->attribute->code);
                        cat_tac(&nodetac, &$3->attribute->code);
                        append_inst_tac(&nodetac, new_tac); 
                        
                        attribute->code=nodetac;

                        Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                        children[0]=$1;
                        children[1]=create_leaf(0, '+', "+", NULL);
                        children[2]=$3;
                        $$=create_node(0, plus_node, "__lvalue", attribute, 3, children);
            }
    | expr '-' expr
            {
                        Attr*  attribute = (Attr*) malloc(sizeof(Attr));

                        struct node_tac*  nodetac=NULL;
                        struct tac*  new_tac = NULL;

                        if($1->attribute->type==0 || $3->attribute->type==0 || $1->attribute->type==TYPE_CHAR || $3->attribute->type==TYPE_CHAR)
                        {
                            yyerror("Tipo invalido.");
                            exit(-1);                            
                        }
                        if($1->attribute->type==TYPE_INT && $3->attribute->type==TYPE_INT)
                        {
                            attribute->type=TYPE_INT;
                            attribute->local=novo_tmp(TYPE_INT);
                            new_tac=create_inst_tac(TAC_EXPR,attribute->local, $1->attribute->local,"SUB", $3->attribute->local);
                        }
                        else
                        {
                            if($1->attribute->type==TYPE_DOUBLE || $3->attribute->type==TYPE_DOUBLE)
                            {
                                attribute->type=TYPE_DOUBLE;
                                attribute->local=novo_tmp(TYPE_DOUBLE);
                            }
                            else
                            {
                                attribute->type=TYPE_REAL;
                                attribute->local=novo_tmp(TYPE_REAL);
                            }
                            new_tac=create_inst_tac(TAC_EXPR,attribute->local, $1->attribute->local,"FSUB", $3->attribute->local);
                        }

                        cat_tac(&nodetac, &$1->attribute->code);
                        cat_tac(&nodetac, &$3->attribute->code);
                        append_inst_tac(&nodetac, new_tac); 
                        
                        attribute->code=nodetac;

                        Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                        children[0]=$1;
                        children[1]=create_leaf(0, '-', "-", NULL);
                        children[2]=$3;
                        $$=create_node(0, minus_node, "__lvalue", attribute, 3, children);
            }
    | expr '*' expr
            {
                        Attr*  attribute = (Attr*) malloc(sizeof(Attr));

                        struct node_tac*  nodetac=NULL;
                        struct tac*  new_tac = NULL;

                        if($1->attribute->type==0 || $3->attribute->type==0 || $1->attribute->type==TYPE_CHAR || $3->attribute->type==TYPE_CHAR)
                        {
                            yyerror("Tipo invalido.");
                            exit(-1);                            
                        }
                        if($1->attribute->type==TYPE_INT && $3->attribute->type==TYPE_INT)
                        {
                            attribute->type=TYPE_INT;
                            attribute->local=novo_tmp(TYPE_INT);
                            new_tac=create_inst_tac(TAC_EXPR,attribute->local, $1->attribute->local,"MUL", $3->attribute->local);
                        }
                        else
                        {
                            if($1->attribute->type==TYPE_DOUBLE || $3->attribute->type==TYPE_DOUBLE)
                            {
                                attribute->type=TYPE_DOUBLE;
                                attribute->local=novo_tmp(TYPE_DOUBLE);
                            }
                            else
                            {
                                attribute->type=TYPE_REAL;
                                attribute->local=novo_tmp(TYPE_REAL);
                            }
                            new_tac=create_inst_tac(TAC_EXPR,attribute->local, $1->attribute->local,"FMUL", $3->attribute->local);
                        }

                        cat_tac(&nodetac, &$1->attribute->code);
                        cat_tac(&nodetac, &$3->attribute->code);
                        append_inst_tac(&nodetac, new_tac); 
                        
                        attribute->code=nodetac;

                        Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                        children[0]=$1;
                        children[1]=create_leaf(0, '*', "*", NULL);
                        children[2]=$3;
                        $$=create_node(0, mult_node, "__lvalue", attribute, 3, children);

            }
    | expr '/' expr
            {
                        Attr*  attribute = (Attr*) malloc(sizeof(Attr));

                        struct node_tac*  nodetac=NULL;
                        struct tac*  new_tac = NULL;
                        
                        if($1->attribute->type==0 || $3->attribute->type==0 || $1->attribute->type==TYPE_CHAR || $3->attribute->type==TYPE_CHAR)
                        {
                            yyerror("Tipo invalido.");
                            exit(-1);                            
                        }
                        if($1->attribute->type==TYPE_INT && $3->attribute->type==TYPE_INT)
                        {
                            attribute->type=TYPE_INT;
                            attribute->local=novo_tmp(TYPE_INT);
                            new_tac=create_inst_tac(TAC_EXPR,attribute->local, $1->attribute->local,"DIV", $3->attribute->local);
                        }
                        else
                        {
                            if($1->attribute->type==TYPE_DOUBLE || $3->attribute->type==TYPE_DOUBLE)
                            {
                                attribute->type=TYPE_DOUBLE;
                                attribute->local=novo_tmp(TYPE_DOUBLE);
                            }
                            else
                            {
                                attribute->type=TYPE_REAL;
                                attribute->local=novo_tmp(TYPE_REAL);
                            }
                            new_tac=create_inst_tac(TAC_EXPR,attribute->local, $1->attribute->local,"FDIV", $3->attribute->local);
                        }

                        cat_tac(&nodetac, &$1->attribute->code);
                        cat_tac(&nodetac, &$3->attribute->code);
                        append_inst_tac(&nodetac, new_tac); 
                        
                        attribute->code=nodetac;

                        Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                        children[0]=$1;
                        children[1]=create_leaf(0, '/', "/", NULL);
                        children[2]=$3;
                        $$=create_node(0, div_node, "__lvalue", attribute, 3, children);
            }
    | '(' expr ')'
            { 
                        
                        Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                        children[0]=create_leaf(0, '(', "(", NULL);
                        children[1]=$2;
                        children[2]=create_leaf(0, ')', ")", NULL);
                        $$=create_node(0, expr_node, "__lvalue", $2->attribute, 3, children);
            }
    | INT_LIT      
            { 
                        Attr*  attribute = (Attr*) malloc(sizeof(Attr));
                        attribute->local=$1;
                        attribute->code=NULL;
                        attribute->type=TYPE_INT;
                        $$ = create_leaf(0, int_node, $1, attribute); 
            } 
    | F_LIT     
            { 
                        Attr*  attribute = (Attr*) malloc(sizeof(Attr));
                        attribute->local=$1;
                        attribute->code=NULL;
                        attribute->type=TYPE_DOUBLE;
                        $$ = create_leaf(0, float_node, $1, attribute); 
            } 
    | lvalue    
            { 
                $$ = $1; 
            }
    | chamaproc { $$ = $1; } 
    ;

chamaproc: IDF '(' listaexpr ')'
            {

                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=create_leaf(0, idf_node, $1, NULL);
                children[1]=create_leaf(0, '(', "(", NULL);
                children[2]=$3;
                children[3]=create_leaf(0, ')', ")", NULL);
                $$=create_node(0, call_proc_node, "__chamaproc", NULL, 4, children);
            }
         ;

enunciado: expr { $$ = $1 ;}
         | IF '(' expbool ')' THEN acoes fiminstcontrole
            {
            
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));
              
                attribute->next=novo_rot(malloc(sizeof(char)*(10)));                
                
                //S → if { B.t := novo_rot; B.f:=novo_rot; }

                $3->attribute->t=novo_rot(malloc(sizeof(char)*(10)));

                if($7->type==fim_ctrl_node)
                    $3->attribute->f=novo_rot(malloc(sizeof(char)*(10)));
                else
                    $3->attribute->f=attribute->next;
                    

                //B then { S1.next := S.next;}
                
                $6->attribute->next=attribute->next;
   
                //S1 else {S2.next:=S.next;}
                
                if($7->attribute!=NULL)
                    $7->attribute->next=attribute->next;

                // percorre nodo expool herdando os atributos de do nodo pai - IF
                gen_attributes_exbool($3);
                // agora jah eh possível sintetizar os atributos

                //S2 {S.code:=B.code ||                
                attribute->code=$3->attribute->code;
                
                //geracod (B.t':')||                
                struct tac* new_tac1 = create_inst_tac(TAC_LABEL,"", $3->attribute->t,"", "");
                append_inst_tac(&attribute->code, new_tac1);
                
                //S1.code ||
                cat_tac(&attribute->code, &$6->attribute->code);

                if($7->type==fim_ctrl_node)
                {                
                    //geracod('goto' S.next) ||
                    struct tac* new_tac2 = create_inst_tac(TAC_GOTO,"", attribute->next,"", "");
                    append_inst_tac(&attribute->code, new_tac2); 

                    //geracod(B.f':')||
                    struct tac* new_tac3 = create_inst_tac(TAC_LABEL,"", $3->attribute->f,"", "");
                    append_inst_tac(&attribute->code, new_tac3);
                    
                    //S2.code || 
                    cat_tac(&attribute->code, &$7->attribute->code);
                
                }

                
                //geracod(S.next ':') }
                struct tac* new_tac4 = create_inst_tac(TAC_LABEL,"", attribute->next,"", "");
                append_inst_tac(&attribute->code, new_tac4); 
               
           
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=create_leaf(0, if_kw_node, "if", NULL);
                children[1]=create_leaf(0, '(', "(", NULL);
                children[2]=$3;
                children[3]=create_leaf(0, ')', ")", NULL);
                children[4]=create_leaf(0, then_kw_node, "then", NULL);
                children[5]=$6;
                children[6]=$7;

                $$=create_node(0, if_node, "__enuciado", attribute, 7, children);
            }
         | WHILE '(' expbool ')' '{' acoes '}'
            { 
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));
              
                attribute->next=novo_rot(malloc(sizeof(char)*(10)));   

                //S → while {B.f := S.next;
                $3->attribute->f=attribute->next;
                
                //B.t := novo_rot;}
                $3->attribute->t=novo_rot(malloc(sizeof(char)*(10)));
                
                //B do
                //S1 { S.begin := novo_rot;
                attribute->begin=novo_rot(malloc(sizeof(char)*(10)));   

                // percorre nodo expool herdando os atributos de do nodo pai - while
                gen_attributes_exbool($3);
                // agora jah eh possível sintetizar os atributos

                //geracod (S.begin ':') ||
                struct tac* new_tac1 = create_inst_tac(TAC_LABEL,"", attribute->begin,"", "");
                append_inst_tac(&attribute->code, new_tac1);
                
                //B.code ||
                cat_tac(&attribute->code, &$3->attribute->code);
                
                //geracod(B.t: ) ||
                struct tac* new_tac2 = create_inst_tac(TAC_LABEL,"",$3->attribute->t,"", "");
                append_inst_tac(&attribute->code, new_tac2);
                
                //S1.code ||
                cat_tac(&attribute->code, &$6->attribute->code);
                               
                //geracod('goto' S.begin) || geracod( S.next ':') }
                struct tac* new_tac3 = create_inst_tac(TAC_GOTO,"",attribute->begin,"", "");
                append_inst_tac(&attribute->code, new_tac3);

                struct tac* new_tac4 = create_inst_tac(TAC_LABEL,"",attribute->next,"", "");
                append_inst_tac(&attribute->code, new_tac4);

                       
            
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=create_leaf(0, while_kw_node, "while", NULL);
                children[1]=create_leaf(0, '(', "(", NULL);
                children[2]=$3;
                children[3]=create_leaf(0, ')', ")", NULL);
                children[4]=create_leaf(0, '{', "{", NULL);
                children[5]=$6;
                children[6]=create_leaf(0, '}', "}", NULL);
                $$=create_node(0, while_node, "__enunciado", attribute, 7, children);
            }
        | IPRINT '(' expr ')'
        {               Attr*  attribute = (Attr*) malloc(sizeof(Attr));

                        

                        cat_tac(&attribute->code, &$3->attribute->code);
                        append_inst_tac(&attribute->code, create_inst_tac(TAC_PRINT,"",$3->attribute->local,"", "")); 
                        
    
                        Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                        children[0]=create_leaf(0, 'i', "print", NULL);
                        children[1]=create_leaf(0, '(', "(", NULL);
                        children[2]=$3;
                        children[3]=create_leaf(0, ')', ")", NULL);
                        $$=create_node(0, print_kw_node, "__lvalue", attribute, 4, children);               
            } 
                      
                               
         ;

fiminstcontrole: END        { $$ = create_leaf(0, end_node, "end", NULL); }
               | ELSE acoes END    
            {
                
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));

                attribute->code=$2->attribute->code;
                
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=create_leaf(0, else_node, "else", NULL);
                children[1]=$2;
                children[2]=create_leaf(0, end_node, "end", NULL);
                $$=create_node(0, fim_ctrl_node, "__fiminstcontrole", attribute, 3, children);
            }
               ;

expbool: TRUE             
            {  
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));
                $$ = create_leaf(0, true_node, "true", attribute); 
            
            }
       | FALSE
            { 

                Attr*  attribute = (Attr*) malloc(sizeof(Attr));
                $$ = create_leaf(0, false_node, "false", attribute); 
              
            }      
       | '(' expbool ')'    
            { 
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));

                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=create_leaf(0, '(', "(", NULL);
                children[1]=$2;
                children[2]=create_leaf(0, ')', ")", NULL);
                $$=create_node(0, assexpbool_node, "__expbool", attribute, 3, children);
            }
       | expbool AND expbool
            {
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));
                
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=$1;
                children[1]=create_leaf(0, and_kw_node, "&&", NULL);
                children[2]=$3;
                $$=create_node(0, and_node, "__expbool", attribute, 3, children);
            }
       | expbool OR expbool
            {
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));
                
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=$1;
                children[1]=create_leaf(0, or_kw_node, "||", NULL);
                children[2]=$3;
                $$=create_node(0, or_node, "__expbool", attribute, 3, children);
            }
       | NOT expbool
            {
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));
                            
                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=create_leaf(0, not_kw_node, "!", NULL);
                children[1]=$2;
                $$=create_node(0, not_node, "__expbool", attribute, 2, children); 
            }
       | expr '>' expr
            {
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));

                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=$1;
                children[1]=create_leaf(0, '>', ">", NULL);
                children[2]=$3;
                $$=create_node(0, relop_node, "__expbool", attribute, 3, children);

            }
       | expr '<' expr
            {
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));

                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=$1;
                children[1]=create_leaf(0, '<', "<", NULL);
                children[2]=$3;
                $$=create_node(0, relop_node, "__expbool", attribute, 3, children);

            }
       | expr LE expr
            {
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));

                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=$1;
                children[1]=create_leaf(0, inf_eq_node, "<=", NULL);
                children[2]=$3;
                $$=create_node(0, relop_node, "__expbool", attribute, 3, children);
            }
       | expr GE expr
            {
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));

                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=$1;
                children[1]=create_leaf(0, sup_eq_node, ">=", NULL);
                children[2]=$3;
                $$=create_node(0, relop_node, "__expbool", attribute, 3, children);
            }
       | expr EQ expr
            {
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));

                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=$1;
                children[1]=create_leaf(0, eq_node, "=", NULL);
                children[2]=$3;
                $$=create_node(0, relop_node, "__expbool", attribute, 3, children);
            }
       | expr NE expr
            {
                Attr*  attribute = (Attr*) malloc(sizeof(Attr));

                Node**  children = (Node**) malloc(MAX_CHILDREN_NUMBER*sizeof(Node*));
                children[0]=$1;
                children[1]=create_leaf(0, neq_node, "!=", NULL);
                children[2]=$3;
                $$=create_node(0, relop_node, "__expbool", attribute, 3, children);
            }
       ;
%%
 /* A partir daqui, insere-se qualqer codigo C necessario.
  */

char* progname;
int lineno;
extern FILE* yyin;

FILE* saida;


void gen_attributes_exbool(Node* n)
{ 
    if(n->type==true_node)
    {
        struct node_tac*  nodetac=NULL;
        struct tac*  new_tac = NULL;

        new_tac=create_inst_tac(TAC_GOTO,"", n->attribute->t,"", "");

        append_inst_tac(&nodetac, new_tac); 
                        
        n->attribute->code=nodetac;
   
    }
    if(n->type==false_node)
    {
        struct node_tac*  nodetac=NULL;
        struct tac*  new_tac = NULL;

        new_tac=create_inst_tac(TAC_GOTO,"", n->attribute->f,"", "");

        append_inst_tac(&nodetac, new_tac); 
   
        n->attribute->code=nodetac;
  
    }
    if(n->type==assexpbool_node)
    {
        // aqui estah invertido em relaçao aos slides, atributos são herdados, ao invés de sintetizados
        n->children[1]->attribute->t=n->attribute->t;
        n->children[1]->attribute->f=n->attribute->f;

        gen_attributes_exbool(n->children[1]);

        // jah code eh sintetizado como estah nos slides
        n->attribute->code=n->children[1]->attribute->code;        

    }
    if(n->type==not_node)
    {
        n->children[1]->attribute->t=n->attribute->f;
        n->children[1]->attribute->f=n->attribute->t;

        gen_attributes_exbool(n->children[1]);

        n->attribute->code=n->children[1]->attribute->code;        
    }
    if(n->type==and_node)
    {
        n->children[0]->attribute->t=novo_rot(malloc(sizeof(char)*(10)));
        n->children[0]->attribute->f=n->attribute->f;

        n->children[2]->attribute->t=n->attribute->t;
        n->children[2]->attribute->f=n->attribute->f;

        gen_attributes_exbool(n->children[0]);
        gen_attributes_exbool(n->children[2]);

        //B.code = B1.code || label(B1.t) || B2.code
        n->attribute->code=n->children[0]->attribute->code;        

        struct tac*  new_tac = create_inst_tac(TAC_LABEL,"", n->children[0]->attribute->t,"", "");

        append_inst_tac(&n->attribute->code, new_tac); 
   
        cat_tac(&n->attribute->code, &n->children[2]->attribute->code);
    }
    if(n->type==or_node)
    {
        n->children[0]->attribute->t=n->attribute->t;
        n->children[0]->attribute->f=novo_rot(malloc(sizeof(char)*(10)));

        n->children[2]->attribute->t=n->attribute->t;
        n->children[2]->attribute->f=n->attribute->f;

        gen_attributes_exbool(n->children[0]);
        gen_attributes_exbool(n->children[2]);

        //B.code = B1.code || label(B1.t) || B2.code
        n->attribute->code=n->children[0]->attribute->code;        

        struct tac*  new_tac = create_inst_tac(TAC_LABEL,"", n->children[0]->attribute->f,"", "");

        append_inst_tac(&n->attribute->code, new_tac); 
   
        cat_tac(&n->attribute->code, &n->children[2]->attribute->code);
    }
    if(n->type==relop_node)
    {
        //B.code = E1.code ||
        n->attribute->code=n->children[0]->attribute->code;        

        //E2.code ||
        cat_tac(&n->attribute->code, &n->children[2]->attribute->code);
        
        //gera_cod(“if” E1.local relop.lexval E2.local “goto” B.t) ||
        struct tac*  new_tac1 =create_inst_tac(TAC_IF,n->attribute->t, n->children[0]->attribute->local,n->children[1]->lexeme, n->children[2]->attribute->local);
        append_inst_tac(&n->attribute->code, new_tac1);
                        
        //gera_cod(“goto” B.f)
        struct tac*  new_tac2 = create_inst_tac(TAC_GOTO,"", n->attribute->f,"", "");
        append_inst_tac(&n->attribute->code, new_tac2);
    
    }
}
void insert_table(Node* n, Node* type)
{
    //printf("type: %d\n",n->type);
    if(n->type==idf_node)
    {
        entry_t* entrada = malloc(sizeof(entry_t));
        //entrada->name = malloc(sizeof(char)*(strlen(n->lexeme) + 1));
        //strcpy(entrada->name, n->lexeme);
        entrada->name = n->lexeme;
        
        if(type->type==int_kw_node)
        {
            entrada->type =TYPE_INT;
            entrada->size =TAM_INT;
            entrada->extra=NULL;
        }
        else if(type->type==real_kw_node)
        {
            entrada->type =TYPE_REAL;
            entrada->size =TAM_REAL;
            entrada->extra=NULL;
        }
        else if(type->type==double_kw_node)
        {
            entrada->type =TYPE_DOUBLE;
            entrada->size =TAM_DOUBLE;
            entrada->extra=NULL;
        }
        else if(type->type==char_kw_node)
        {
            entrada->type =TYPE_CHAR;
            entrada->size =TAM_CHAR;
            entrada->extra=NULL;
        }
        else if(type->type==tipo_list_node)
        {   //(7 *8)+(1*4)+(2 *1)-5*8 -0*4 -1*1= 16+4+1=21
            int tam=1;
            int offset=0;
            struct array_info* arr = type->attribute->array;
            while(arr!=NULL)
            {
                offset=offset+tam*arr->start;
                arr->off=tam;
                tam*=arr->tam;
                arr=arr->next;
            }

            if(type->children[0]->type==int_kw_node)
            {
                entrada->type =TYPE_INT;
                entrada->size =TAM_INT * tam;
            }
            else if(type->children[0]->type==real_kw_node)
            {
                entrada->type =TYPE_REAL;
                entrada->size =TAM_REAL * tam;
                entrada->extra=NULL;
            }
            else if(type->children[0]->type==double_kw_node)
            {
                entrada->type =TYPE_DOUBLE;
                entrada->size =TAM_DOUBLE * tam;
                entrada->extra=NULL;
            }
            else if(type->children[0]->type==char_kw_node)
            {
                entrada->type =TYPE_CHAR;
                entrada->size =TAM_CHAR * tam;
                entrada->extra=NULL;
            }
            type->attribute->array->offset=offset;        
            entrada->extra=type->attribute->array;
        }
        
        entrada->desloc = deslocamento;
        deslocamento+=entrada->size;
        insert(&symbol_table, entrada);
    }
    else if(n->type==decl_list_node)
    {
        insert_table(n->children[0],type);
        insert_table(n->children[2],type);
    }


 
}

int get_deslocamento()
{
    return deslocamento;
}

int main(int argc, char* argv[]) 
{

   init_table(&symbol_table);

   if (argc != 2) {
     printf("uso: %s <input_file>. Try again!\n", argv[0]);
     exit(-1);
   }
   yyin = fopen(argv[1], "r");
   if (!yyin) {
     printf("Uso: %s <input_file>. Could not find %s. Try again!\n", 
         argv[0], argv[1]);
     exit(-1);
   }

   progname = argv[0];

   if (!yyparse()) 
   {
      printf("OKAY.\n"); 
      print_tree(syntax_tree,0); /* se o parser aceita a entrada então imprime a árvore a partir do nó raiz */
      
      
      
      
      saida = fopen("code.pico", "w");
        
        if(syntax_tree->attribute!=NULL) 
            print_tac(saida, syntax_tree->attribute->code);
 
        print_table(symbol_table);
  
      deep_free_node(syntax_tree) ;
      free_table(&symbol_table);      
   }
   else 
      printf("ERROR.\n");

   return(0);
}

yyerror(char* s) {
  fprintf(stderr, "%s: %s", progname, s);
  fprintf(stderr, "line %d\n", lineno);
}
